package push

import (
	"encoding/json"
	"gitee.com/yysf_xin/dplog/pkg/slog"
	"gitee.com/yysf_xin/go-common/db"
	"gitee.com/yysf_xin/go-common/rest"
	"gitee.com/yysf_xin/go-common/tools"
	"gitee.com/yysf_xin/go-notifier"
	"net/http"
	"strconv"
	"strings"
	"time"
)

type Server struct {
	Db       *db.Client
	push     *notifier.Notifier
	chanel   chan *MsgRef
	Template string
	Em       slog.Emitter
}
type MsgLog struct {
	db.Model
	Msg
}

func NewServer(db *db.Client, push *notifier.Notifier) (s *Server, err error) {
	if db.Cfg.Upgrade {
		var log MsgLog
		err = db.DB.AutoMigrate(&log)
		if err != nil {
			return
		}
	}
	s = &Server{
		Db:   db,
		push: push,
	}
	if push != nil {
		s.chanel = make(chan *MsgRef, 10)
	}
	return
}

func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
	var m Msg
	err := json.NewDecoder(request.Body).Decode(&m)
	if err == nil {
		// 走日志聚合
		if s.Em != nil {
			ref := slog.NewRef(&m.Msg)
			ref.Meta = m.Meta
			ref.Count = m.Count
			s.Em.FireMsg(ref)
		} else {
			err = s.saveMsg(&m)
			s.send(&m)
		}
	}
	if err != nil {
		writer.WriteHeader(400)
		str := err.Error()
		_, _ = writer.Write(tools.StringToBytes(str))
	} else {
		str := strconv.FormatUint(uint64(m.MsgId), 10)
		_, _ = writer.Write(tools.StringToBytes(str))
	}
}

func (s *Server) DoNotify(ref *MsgRef) {
	_ = s.saveMsg(&ref.Msg)
	if s.push != nil {
		ref.Ref.Retain()
		s.chanel <- ref
	}
}

func (s *Server) Run() {
	for {
		m := <-s.chanel
		// tools.Log.Println("send msg", m.Msg.Msg.Message)
		s.send(&m.Msg)
		m.Ref.Release()
	}
}

func (s *Server) send(msg *Msg) {
	err := s.push.SendByCode(s.Template, nil, msg)
	if err != nil {
		tools.Log.Println(err)
	}

}

func (s *Server) saveMsg(m *Msg) (err error) {
	if s.Db == nil {
		return nil
	}
	traceID := m.Msg.TraceID
	traceIndex := strings.Index(traceID, ",")
	if traceIndex != -1 {
		traceID = traceID[:traceIndex]
	}
	// 精简traceId
	m.Msg.TraceID = traceID

	var log MsgLog
	if m.MsgId > 0 {
		log.Id = m.MsgId
		log.Count = m.Count
		log.Last = m.Last
		err = s.Db.DB.Model(&log).Updates(&log).Error
	} else {
		log.Msg = *m
		//log.Msg.Msg.TraceID = traceID
		err = s.Db.DB.Save(&log).Error
	}

	if err != nil {
		tools.Log.Println(err)
		return
	}
	m.MsgId = log.Id

	return
}

func (s *Server) ListLog(w http.ResponseWriter, r *http.Request) {
	q := r.URL.Query()
	var log MsgLog
	log.Msg.Msg.TraceID = q.Get("TraceID")
	log.Msg.Msg.AppName = q.Get("AppName")
	log.Msg.Meta.Env = q.Get("Env")
	timeStr := q.Get("Time")
	if timeStr != "" {
		var t db.Time
		err := t.UnmarshalJSON(tools.StringToBytes(timeStr))
		if err != nil {
			log.Msg.Msg.Time = time.Time(t)
		}
	}

	var logs []*MsgLog

	var total int64
	s.Db.DB.Model(&log).Where(&log).Count(&total)
	_ = db.Paginate(r)(s.Db.DB.Model(&log).Where(&log).Order("id desc")).Find(&logs).Error
	rest.RenderJSONTotal(w, logs, int(total))

}
